#pragma once
#include "Utilities.h"
#include "PictureImpl.h"
#include "ThreadRunner.h"
#include "Logger.h"
#include "ThresholdingIterator.h"
#include "Sketch.h"

typedef std::valarray<BYTE> ByteArray;

enum ViewID
{ kViewOriginal = 0, kViewGradient, kViewGradientSimple, kViewC2Gradient, 
	kViewGradientNoBrightSpots, kViewGradientCross, kViewGradientSensitivity,
	kViewThreshold, kViewBlank,
	kViewC2Gradient00, kViewC2Gradient01, kViewC2Gradient10, kViewC2Gradient11,
	kViewIDsCount 
};

enum OutlinesFilterIndex
{
	kIndexSaveToSVG = 1,
	kIndexSaveToVML,
	kIndexSaveToPDF,
	kIndexSaveToMetafile,
	kBiggestIndexOfSaveTo = kIndexSaveToMetafile
};

struct IWICBitmapFrameDecode;
struct IWICImagingFactory;
struct IWICBitmapSource;

class Picture : public ThreadRunner::Runnable
{
public:

	class EventHandler
	{
	public:
		virtual void NotifyChange(int notificationID) const = 0;
	};

	Picture(Logger& logger);
	~Picture(void);

	int GetRawWidth() const;
	int GetRawHeight() const;

	void SetEventHandler(EventHandler* handler);
	BOOL Load(const TCHAR* path);

	// saving to files
	BOOL SaveCurrentViewTo(const TCHAR* path) const;

	ViewID GetView() const;

	void Draw(HDC, const RECT&) const;
	void SetScale(float);
	void SelectViewAspect(ViewID);

	bool SetBlur(float);
	bool SetThreshold(float);
	bool SetNoise(float);
	bool SetClutterSuppression(float);
	bool SetCurvatureCalculationToken(int);

	float GetScale() const;
	int GetWidth() const;
	int GetHeight() const;
	bool CanSaveBitmap() const;

	void NotifyChange(int notificationID) const;

	bool UpdateDisplayBitmapsLazily();

	Sketch& GetSketch();
	const Sketch& GetSketch() const;

	// the shift between the origin of coordinates 
	void GetDotShift(float& outShiftX, float& outShiftY) const;
private:
	void Run(ThreadRunner::Controller& controller);

	void DrawBitmap(HDC, HBITMAP hBitmap, const RECT& updateRect) const;
	void DrawMargins(HDC, const RECT& updateRect) const;

	void Cleanup();
	void ClearBitmapAtIndex(int index);
	void Log(const TCHAR*);

private:
// data -----------------------------------------
	PictureImpl mBitmap;
	EventHandler* mHandler; 

	HBITMAP mBitmaps[kViewIDsCount];

	float mScale;
	ViewID mSelectedViewID;
	
	float mThreshold, mBlur, mNoise, mClutterSuppression;
	int mCurvatureCalculationToken;
	
	bool mIsEnabledSavePixels;

	union {
		BITMAPINFO i; 
		BYTE ptr[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];
	} mGrayInfo;

	int mHighlightedStrokeIndex;
	RECT mPreviousInvalidateRect;

	Sketch mSketch;

	Logger& mLogger;

	HBITMAP CreateBitmap();
	static HBITMAP LoadUsingDecoders(const TCHAR* filePath);
	static HBITMAP CreateSRGBBitmapHandle(IWICBitmapFrameDecode*, IWICImagingFactory*);
	static HBITMAP CreateHBitmap(IWICBitmapSource*);
};